package com.guoheng.hazard.sys.service.impl.hazard;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.guoheng.hazard.common.base.Result;
import com.guoheng.hazard.common.enums.ErrorCodeEnum;
import com.guoheng.hazard.common.util.StringUtils;
import com.guoheng.hazard.config.InfluxDBConfig;
import com.guoheng.hazard.sys.mapper.entpr.EntprBasicInfoMapper;
import com.guoheng.hazard.sys.mapper.entpr.ProductionPlaceMapper;
import com.guoheng.hazard.sys.mapper.entpr.StorageRoomMapper;
import com.guoheng.hazard.sys.mapper.entpr.StorageTankMapper;
import com.guoheng.hazard.sys.mapper.hazard.MajorHazardInfoMapper;
import com.guoheng.hazard.sys.mapper.hazard.MonitorSensorMapper;
import com.guoheng.hazard.sys.model.dto.entpr.EntprScopeDTO;
import com.guoheng.hazard.sys.model.dto.hazard.MonitorSensorInsertDTO;
import com.guoheng.hazard.sys.model.dto.hazard.MonitorSensorPageDTO;
import com.guoheng.hazard.sys.model.dto.hazard.MonitorSensorUpdateDTO;
import com.guoheng.hazard.sys.model.entity.entpr.EntprBasicInfo;
import com.guoheng.hazard.sys.model.entity.entpr.ProductionPlace;
import com.guoheng.hazard.sys.model.entity.entpr.StorageRoom;
import com.guoheng.hazard.sys.model.entity.entpr.StorageTank;
import com.guoheng.hazard.sys.model.entity.hazard.InfluxdbSensorData;
import com.guoheng.hazard.sys.model.entity.hazard.MajorHazardInfo;
import com.guoheng.hazard.sys.model.entity.hazard.MonitorSensor;
import com.guoheng.hazard.sys.service.hazard.MonitorSensorService;
import lombok.Data;
import org.influxdb.InfluxDB;
import org.influxdb.dto.Point;
import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.guoheng.hazard.common.enums.PartTypeEnum.PART_TYPE_ONE;
import static com.guoheng.hazard.common.enums.SensorTypeEnum.*;
import static com.guoheng.hazard.common.enums.TankTypeEnum.TANK_TYPE_ONE;

/**
 * 类功能描述:　MonitorSensorServiceImpl
 *
 * @author Eternal
 * @date 2019-11-20 17:02
 */
@Service
@EnableScheduling
public class MonitorSensorServiceImpl implements MonitorSensorService {

    @Resource
    MonitorSensorMapper monitorSensorMapper;

    @Resource
    MajorHazardInfoMapper majorHazardInfoMapper;

    @Resource
    StorageTankMapper storageTankMapper;

    @Resource
    StorageRoomMapper storageRoomMapper;

    @Resource
    ProductionPlaceMapper productionPlaceMapper;

    @Resource
    EntprBasicInfoMapper entprBasicInfoMapper;

    @Resource
    InfluxDB influxDB;

    @Resource
    InfluxDBConfig influxDBConfig;

    @Override
    public Result getMonitorSensors(Long entprId, String entprName, String cameraNo, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<MonitorSensorPageDTO> monitorSensors = monitorSensorMapper.getMonitorSensors(entprId, entprName, cameraNo);
        for (MonitorSensorPageDTO sensor : monitorSensors) {
            getPartName(sensor);
        }
        PageInfo<MonitorSensorPageDTO> monitorSensorPageInfo = new PageInfo<>(monitorSensors);
        return Result.success(monitorSensorPageInfo);
    }

    @Override
    public Result updateMonitorSensor(MonitorSensorUpdateDTO majorMonitorSensorUpdateDTO) {
        MonitorSensor monitorSensor = new MonitorSensor();
        BeanUtils.copyProperties(majorMonitorSensorUpdateDTO, monitorSensor);
        Integer partType = monitorSensor.getPartType();
        // 储罐
        if (partType != null && partType.equals(PART_TYPE_ONE.getCode())) {
            // 储罐id
            Long partId = monitorSensor.getPartId();
            // 查询储罐信息
            StorageTank entprTankById = storageTankMapper.getEntprTankById(partId);
            // 得到储罐类型
            Integer tankType = entprTankById.getTankType();
            // 修改前的传感器信息
            MonitorSensor beforeSensor = monitorSensorMapper.selectByPrimaryKey(monitorSensor.getId());
            // 传感器类型被修改
            if (!beforeSensor.getSensorType().equals(monitorSensor.getSensorType())) {
                // 查询这个储罐上有什么传感器（修改应排除自己）
                List<MonitorSensor> sensorByPartId = monitorSensorMapper.getSensorByPartId(monitorSensor.getEntprId(), partId, monitorSensor.getId());
                for (MonitorSensor sensor : sensorByPartId) {
                    // 储罐上同一种类型的传感器不能存在两种
                    if (monitorSensor.getSensorType().equals(sensor.getSensorType())) {
                        return Result.failure(ErrorCodeEnum.SYS_ERR_TANK_SENSOR_REPEAT);
                    }
                }

                if (!tankType.equals(TANK_TYPE_ONE.getCode())) {
                    // 其他储罐，只能新增温度，压力，液位传感器
                    if (!monitorSensor.getSensorType().equals(SENSOR_TYPE_ONE.getCode()) && !monitorSensor.getSensorType().equals(SENSOR_TYPE_TWO.getCode()) && !monitorSensor.getSensorType().equals(SENSOR_TYPE_THREE.getCode())) {
                        return Result.failure(ErrorCodeEnum.SYS_ERR_SENSOR_TYPE);
                    }
                }
            }
        }
        // 判断传感器编号是否修改
        MonitorSensor monitorSensor1 = monitorSensorMapper.selectByPrimaryKey(monitorSensor.getId());
        // 修改了
        if (!monitorSensor1.getSensorNo().equals(monitorSensor.getSensorNo())) {
            // 传感器编号不能重复
            List<MonitorSensorPageDTO> monitorSensors = monitorSensorMapper.getMonitorSensors(monitorSensor.getEntprId(), null, null);
            for (MonitorSensorPageDTO sensor : monitorSensors) {
                if (sensor.getSensorNo().equals(monitorSensor.getSensorNo())) {
                    return Result.failure(ErrorCodeEnum.SYS_ERR_SENSOR_REPEAT);
                }
            }
        }
        monitorSensorMapper.updateByPrimaryKeySelective(monitorSensor);
        return Result.success();
    }

    @Override
    public Result insertMonitorSensor(MonitorSensorInsertDTO monitorSensorInsertDTO) {
        MonitorSensor monitorSensor = new MonitorSensor();
        BeanUtils.copyProperties(monitorSensorInsertDTO, monitorSensor);
        monitorSensor.setDelFlag(false);
        Integer partType = monitorSensor.getPartType();
        // 储罐
        if (partType != null && partType.equals(PART_TYPE_ONE.getCode())) {
            // 储罐id
            Long partId = monitorSensor.getPartId();
            // 查询储罐信息
            StorageTank entprTankById = storageTankMapper.getEntprTankById(partId);
            // 得到储罐类型
            Integer tankType = entprTankById.getTankType();
            // 查询这个储罐上有什么传感器
            List<MonitorSensor> sensorByPartId = monitorSensorMapper.getSensorByPartId(monitorSensor.getEntprId(), partId, null);
            for (MonitorSensor sensor : sensorByPartId) {
                // 储罐上同一种类型的传感器不能存在两种
                if (monitorSensor.getSensorType().equals(sensor.getSensorType())) {
                    return Result.failure(ErrorCodeEnum.SYS_ERR_TANK_SENSOR_REPEAT);
                }
            }

            if (!tankType.equals(TANK_TYPE_ONE.getCode())) {
                // 其他储罐，只能新增温度，压力，液位传感器
                if (!monitorSensor.getSensorType().equals(SENSOR_TYPE_ONE.getCode()) && !monitorSensor.getSensorType().equals(SENSOR_TYPE_TWO.getCode()) || !monitorSensor.getSensorType().equals(SENSOR_TYPE_THREE.getCode())) {
                    return Result.failure(ErrorCodeEnum.SYS_ERR_SENSOR_TYPE);
                }
            }
        }
        // 传感器编号不能重复
        List<MonitorSensorPageDTO> monitorSensors = monitorSensorMapper.getMonitorSensors(monitorSensor.getEntprId(), null, null);
        for (MonitorSensorPageDTO sensor : monitorSensors) {
            if (sensor.getSensorNo().equals(monitorSensor.getSensorNo())) {
                return Result.failure(ErrorCodeEnum.SYS_ERR_SENSOR_REPEAT);
            }
        }
        monitorSensorMapper.insertSelective(monitorSensor);
        return Result.success();
    }

    @Override
    public Result deleteMonitorSensor(Long id) {
        monitorSensorMapper.deleteByPrimaryKey(id);
        return Result.success();
    }

    @Override
    public Result getMonitorSensor(Long id) {
        MonitorSensorPageDTO sensor = new MonitorSensorPageDTO();
        MonitorSensor monitorSensor = monitorSensorMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(monitorSensor, sensor);
        getPartName(sensor);
        Long entprId = monitorSensor.getEntprId();
        EntprBasicInfo entprBasicInfo = entprBasicInfoMapper.getEntprBasicInfoById(entprId);
        String entprScope = entprBasicInfo.getEntprScope();
        if (StringUtils.isNotEmpty(entprScope)) {
            entprScope = "{\"data\":" + entprScope + "}";
            JSONObject jsonObject = JSON.parseObject(entprScope);
            JSONArray jsonArray = jsonObject.getJSONArray("data");
            List<EntprScopeDTO> entprScopeDTOS = jsonArray.toJavaList(EntprScopeDTO.class);
            sensor.setEntprScope(entprScopeDTOS);
        } else {
            sensor.setEntprScope(new ArrayList<>());
        }
        return Result.success(sensor);
    }

    @Override
    public Result sensorData(Long entprId, String sensorNo, Long beginTime, Long endTime, Integer pageNum, Integer pageSize) {
        SimpleDateFormat day = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dayAndTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 查询传感器列表
        String begin = "";
        String end = "";
        if (beginTime != null) {
            Date date = new Date(beginTime);
            begin = dayAndTime.format(date);
        } else {
            // 默认查当天
            Date date = new Date();
            begin = day.format(date) + " 00:00:00";
        }
        if (endTime != null) {
            Date date = new Date(endTime);
            end = dayAndTime.format(date);
        } else {
            // 默认查当天
            Date date = new Date();
            end = day.format(date) + " 23:59:59";
        }
        // 查询总条数
        String count = "select count(sensorId) from " + influxDBConfig.getMeasurement() + " where time < " + "'" + end + "' and time >" + "'" + begin + "'";

        String sql = "select * from " + influxDBConfig.getMeasurement() + " where time < " + "'" + end + "' and time >" + "'" + begin + "'";
        if (entprId != null) {
            sql += "and entprId = " + "'" + entprId + "'";
            count += "and entprId = " + "'" + entprId + "'";
        }
        if (StringUtils.isNotEmpty(sensorNo)) {
            sql += "and sensorNo = " + "'" + sensorNo + "'";
            count += "and sensorNo = " + "'" + sensorNo + "'";
        }

        sql += " order by time desc limit " + pageSize + " offset " + (pageNum - 1) * pageSize;
        // influxDB时区
        sql += " tz('Asia/Shanghai')";
        count += " tz('Asia/Shanghai')";
        List<Map> counts = query(influxDB, count, Map.class);
        List<InfluxdbSensorData> sensorData = query(influxDB, sql, InfluxdbSensorData.class);
        for (InfluxdbSensorData sensorDatum : sensorData) {
            String time = sensorDatum.getTime();
            BigDecimal bd = new BigDecimal(time);
            sensorDatum.setTime(bd.toPlainString());
        }

        PageInfo<InfluxdbSensorData> influxdbSensorDataPageInfo = new PageInfo<>(sensorData);
        influxdbSensorDataPageInfo.setPageNum(pageNum);
        influxdbSensorDataPageInfo.setPageSize(pageSize);
        if (CollectionUtil.isNotEmpty(counts)) {
            Integer total = (int) (Double.parseDouble(counts.get(0).get("count").toString()));
            // 总条数
            influxdbSensorDataPageInfo.setTotal(total);
            // 总页数
            influxdbSensorDataPageInfo.setPages(total / pageSize);
        }

        return Result.success(influxdbSensorDataPageInfo);
    }

    /**
     * 方法功能描述: 置入重大危险源名称和组成名称
     *
     * @param sensor
     */
    private void getPartName(MonitorSensorPageDTO sensor) {
        Long majorHazardId = sensor.getMajorHazardId();
        // 查询重大危险源名称
        if (majorHazardId != null) {
            MajorHazardInfo majorHazardInfo = majorHazardInfoMapper.selectByPrimaryKey(majorHazardId);
            if (majorHazardInfo != null) {
                sensor.setMajorHazardName(majorHazardInfo.getMajorHazardName());
            }
            Integer partType = sensor.getPartType();
            Long partId = sensor.getPartId();
            if (partId != null && partType != null) {
                switch (partType) {
                    case 1:
                        // 储罐
                        StorageTank tank = storageTankMapper.getEntprTankById(partId);
                        sensor.setPartName(tank.getTankName());
                        sensor.setPartNo(tank.getTankNo());
                        break;
                    case 2:
                        // 库区
                        StorageRoom room = storageRoomMapper.getEntprRoomById(partId);
                        sensor.setPartName(room.getRoomName());
                        sensor.setPartNo(room.getRoomNo());
                        break;
                    case 3:
                        // 生产场所
                        ProductionPlace place = productionPlaceMapper.getPlaceById(partId);
                        sensor.setPartName(place.getPlaceName());
                        sensor.setPartNo(place.getPlaceNo());
                        break;
                    default:
                        break;
                }
            }
        }
    }

    /**
     * 查询
     *
     * @param command 查询语句
     * @return
     */
    public <T> List<T> query(InfluxDB influxDB, String command, Class<T> clazz) {
        JSONArray resultArr = new JSONArray();
        QueryResult query = influxDB.query(new Query(command, influxDBConfig.getDatabase()), TimeUnit.MILLISECONDS);
        for (QueryResult.Result result : query.getResults()) {
            List<QueryResult.Series> series = result.getSeries();
            if (series == null) {
                continue;
            }
            for (QueryResult.Series serie : series) {
                List<List<Object>> values = serie.getValues();
                List<String> colums = serie.getColumns();
                Map<String, String> tags = serie.getTags();

                // 封装查询结果
                for (int i = 0; i < values.size(); ++i) {
                    JSONObject jsonData = new JSONObject();
                    if (tags != null && tags.keySet().size() > 0) {
                        tags.forEach((k, v) -> jsonData.put(k, v));
                    }
                    for (int j = 0; j < colums.size(); ++j) {
                        jsonData.put(colums.get(j), values.get(i).get(j));
                    }
                    resultArr.add(jsonData);
                }
            }
        }
        return JSONObject.parseArray(resultArr.toJSONString(), clazz);
    }

}
